<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>阅读React源码前的序章 | 技术文档</title>
    <meta name="generator" content="VuePress 1.9.9">
    
    <meta name="description" content="technology-review">
    <meta name="theme-color" content="#3eaf7c">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    
    <link rel="preload" href="/tech-document/assets/css/0.styles.afad9826.css" as="style"><link rel="preload" href="/tech-document/assets/js/app.7336957d.js" as="script"><link rel="preload" href="/tech-document/assets/js/2.4e1184b4.js" as="script"><link rel="preload" href="/tech-document/assets/js/40.cc2c8a0d.js" as="script"><link rel="preload" href="/tech-document/assets/js/12.c2ba2865.js" as="script"><link rel="prefetch" href="/tech-document/assets/js/10.403778a6.js"><link rel="prefetch" href="/tech-document/assets/js/11.1b3238dc.js"><link rel="prefetch" href="/tech-document/assets/js/13.10289b8b.js"><link rel="prefetch" href="/tech-document/assets/js/14.d292f43c.js"><link rel="prefetch" href="/tech-document/assets/js/15.2194d6d3.js"><link rel="prefetch" href="/tech-document/assets/js/16.42e9ba11.js"><link rel="prefetch" href="/tech-document/assets/js/17.a49afd61.js"><link rel="prefetch" href="/tech-document/assets/js/18.98476456.js"><link rel="prefetch" href="/tech-document/assets/js/19.29a251d2.js"><link rel="prefetch" href="/tech-document/assets/js/20.ca55bb01.js"><link rel="prefetch" href="/tech-document/assets/js/21.ae42376a.js"><link rel="prefetch" href="/tech-document/assets/js/22.b1bc092f.js"><link rel="prefetch" href="/tech-document/assets/js/23.38f4ebdf.js"><link rel="prefetch" href="/tech-document/assets/js/24.8c3f712c.js"><link rel="prefetch" href="/tech-document/assets/js/25.317efa81.js"><link rel="prefetch" href="/tech-document/assets/js/26.afeef7fe.js"><link rel="prefetch" href="/tech-document/assets/js/27.44fccbaf.js"><link rel="prefetch" href="/tech-document/assets/js/28.290da4aa.js"><link rel="prefetch" href="/tech-document/assets/js/29.fa50ae0a.js"><link rel="prefetch" href="/tech-document/assets/js/3.414f2d7e.js"><link rel="prefetch" href="/tech-document/assets/js/30.88d887a4.js"><link rel="prefetch" href="/tech-document/assets/js/31.567937c9.js"><link rel="prefetch" href="/tech-document/assets/js/32.27fa7a1a.js"><link rel="prefetch" href="/tech-document/assets/js/33.4eb80605.js"><link rel="prefetch" href="/tech-document/assets/js/34.cf229122.js"><link rel="prefetch" href="/tech-document/assets/js/35.945a7237.js"><link rel="prefetch" href="/tech-document/assets/js/36.d0a4767e.js"><link rel="prefetch" href="/tech-document/assets/js/37.4c6954a0.js"><link rel="prefetch" href="/tech-document/assets/js/38.2bccf61b.js"><link rel="prefetch" href="/tech-document/assets/js/39.2040339f.js"><link rel="prefetch" href="/tech-document/assets/js/4.254b04cb.js"><link rel="prefetch" href="/tech-document/assets/js/41.61cf17ce.js"><link rel="prefetch" href="/tech-document/assets/js/42.b38eb7ca.js"><link rel="prefetch" href="/tech-document/assets/js/43.4ea8ba50.js"><link rel="prefetch" href="/tech-document/assets/js/5.44a12058.js"><link rel="prefetch" href="/tech-document/assets/js/6.237b9cc2.js"><link rel="prefetch" href="/tech-document/assets/js/7.d32d6951.js"><link rel="prefetch" href="/tech-document/assets/js/8.4049e9dd.js"><link rel="prefetch" href="/tech-document/assets/js/9.bec82895.js">
    <link rel="stylesheet" href="/tech-document/assets/css/0.styles.afad9826.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/tech-document/" class="home-link router-link-active"><!----> <span class="site-name">技术文档</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/tech-document/" class="nav-link">
  首页
</a></div><div class="nav-item"><a href="/tech-document/archive/" class="nav-link">
  文章归档
</a></div><div class="nav-item"><a href="/tech-document/css/" class="nav-link">
  HTML/CSS
</a></div><div class="nav-item"><a href="/tech-document/javascript/" class="nav-link">
  Javascript
</a></div><div class="nav-item"><a href="/tech-document/react/" class="nav-link router-link-active">
  React
</a></div><div class="nav-item"><a href="/tech-document/vue/" class="nav-link">
  Vue
</a></div><div class="nav-item"><a href="/tech-document/typescript/" class="nav-link">
  Typescript
</a></div><div class="nav-item"><a href="/tech-document/webpack/" class="nav-link">
  Webpack
</a></div><div class="nav-item"><a href="/tech-document/algorithm/" class="nav-link">
  算法
</a></div><div class="nav-item"><a href="/tech-document/network/" class="nav-link">
  网络知识
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="个人博客" class="dropdown-title"><span class="title">个人博客</span> <span class="arrow down"></span></button> <button type="button" aria-label="个人博客" class="mobile-dropdown-title"><span class="title">个人博客</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://blog.csdn.net/qq_39583550" target="_blank" rel="noopener noreferrer" class="nav-link external">
  CSDN
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://cjperfect.gitee.io/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  个人工具
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/tech-document/" class="nav-link">
  首页
</a></div><div class="nav-item"><a href="/tech-document/archive/" class="nav-link">
  文章归档
</a></div><div class="nav-item"><a href="/tech-document/css/" class="nav-link">
  HTML/CSS
</a></div><div class="nav-item"><a href="/tech-document/javascript/" class="nav-link">
  Javascript
</a></div><div class="nav-item"><a href="/tech-document/react/" class="nav-link router-link-active">
  React
</a></div><div class="nav-item"><a href="/tech-document/vue/" class="nav-link">
  Vue
</a></div><div class="nav-item"><a href="/tech-document/typescript/" class="nav-link">
  Typescript
</a></div><div class="nav-item"><a href="/tech-document/webpack/" class="nav-link">
  Webpack
</a></div><div class="nav-item"><a href="/tech-document/algorithm/" class="nav-link">
  算法
</a></div><div class="nav-item"><a href="/tech-document/network/" class="nav-link">
  网络知识
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="个人博客" class="dropdown-title"><span class="title">个人博客</span> <span class="arrow down"></span></button> <button type="button" aria-label="个人博客" class="mobile-dropdown-title"><span class="title">个人博客</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://blog.csdn.net/qq_39583550" target="_blank" rel="noopener noreferrer" class="nav-link external">
  CSDN
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://cjperfect.gitee.io/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  个人工具
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>React</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/tech-document/react/" aria-current="page" class="sidebar-link">React中小知识点</a></li><li><a href="/tech-document/react/0浅谈副作用.html" class="sidebar-link">浅谈React副作用</a></li><li><a href="/tech-document/react/1浅谈Fiber是什么，解决了什么问题.html" class="sidebar-link">浅谈Fiber是什么，解决了什么问题</a></li><li><a href="/tech-document/react/2浅谈Fiber架构下React是如何更新的.html" class="sidebar-link">浅谈Fiber架构下React是如何更新的</a></li><li><a href="/tech-document/react/3浅谈ReactFiber是如何实现更新过程可控.html" class="sidebar-link">浅谈React Fiber如何实现更新过程可控</a></li><li><a href="/tech-document/react/Fiber工作原理.html" class="sidebar-link">浅谈React Fiber工作原理</a></li><li><a href="/tech-document/react/React架构演变.html" class="sidebar-link">React架构演变</a></li><li><a href="/tech-document/react/阅读React源码前的序章.html" class="active sidebar-link">阅读React源码前的序章</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><div class="custom-header" data-v-46893521><h1 class="title" data-v-46893521></h1> <div class="name" data-v-46893521>
    作者:
    <span data-v-46893521></span></div> <div class="categories" data-v-46893521>
    分类:
    </div> <div class="tags" data-v-46893521>
    标签:
    </div> <div class="date" data-v-46893521>
    创建时间:
    <span data-v-46893521></span></div></div> <h2 id="浏览器的一帧"><a href="#浏览器的一帧" class="header-anchor">#</a> 浏览器的一帧</h2> <p>浏览器中，页面都是一帧一帧的绘制出来的，渲染的帧率和设备的刷新率是一致的，以常用的显示器为例，它的刷新率是 60 次 / 秒，也就是说当每秒绘制的帧数(FPS) &gt;= 60，页面渲染就是流畅的，一旦小于了就会出现卡顿的情况。
<img src="https://img-blog.csdnimg.cn/bf686392709241199d7b0fafa7d9527f.png" alt="在这里插入图片描述"> <strong>为什么每一帧需要 16.6ms</strong></p> <ul><li>1s 绘制 60 帧，那么每一帧所要占用的时间就是 1000ms / 60 ≈ 16.6ms。</li></ul> <p><strong>分析每一帧浏览器具体做了哪些事情：</strong></p> <ol><li>首先处理输入事件，能够让用户尽早的得到反馈。</li> <li>处理定时器，需要检查定时器是否到了指定的时间，如果到了就要执行对应的回调函数。</li> <li>开始每一帧，执行对应的事件。</li> <li>执行请求动画帧<code>requestAnimationFrame</code>，每次绘制之前，执行<code>requestAnimationFrame</code>的回调函数。</li> <li>进行页面的布局。</li> <li>进行绘制渲染外观。</li> <li>一帧的事情都干完了，接下来就是空闲时间了，这里执行<code>requestIdleCallback</code>的回调函数。</li></ol> <p>并不是每一帧都有空余时间的, 主要是要看到前面 16.6ms 是否做完了前面的事情，如果有并且提前做完了才有空闲时间。</p> <h2 id="浏览器的空闲时间是什么"><a href="#浏览器的空闲时间是什么" class="header-anchor">#</a> 浏览器的空闲时间是什么？</h2> <p>浏览器的一个原生 API，<code>requestIdleCallback</code>函数
<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback" target="_blank" rel="noopener noreferrer">MDN 的一段介绍<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>说白了，就是捡浏览器的空闲时间来执行任务，但并不是每一帧都有空闲时间的，如果浏览器一直处于非常忙碌的状态，那么 requestIdleCallback 注册的任务永远都不会执行的。一般用来执行优先级比较低的任务。</p> <h3 id="requestidlecallback-的使用"><a href="#requestidlecallback-的使用" class="header-anchor">#</a> requestIdleCallback 的使用</h3> <div class="language-js extra-class"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">requestIdleCallback</span><span class="token punctuation">(</span>callback<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><strong>参数：</strong></p> <p>callback()：回调函数也就是空闲时需要执行的任务，接收一个 IdleDeadline 对象作为入参。其中 IdleDeadline 对象包含：</p> <ul><li>didTimeout，布尔值，表示任务是否超时，结合 timeRemaining 使用。</li> <li>timeRemaining()，表示当前帧剩余的时间，也可理解为留给任务的时间还有多少。</li></ul> <p>options：目前 options 只有一个参数</p> <ul><li>timeout 。表示超过这个时间后，如果任务还没执行，则强制执行，不必等待空闲。</li></ul> <p><strong>使用案例</strong></p> <p>任务队列中有四个任务，要在浏览器空闲时间时候执行。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> taskQueue <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;task1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;task2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;task3&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;task4&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">performUnitOfWork</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">deadline</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">这一帧还剩余多少时间</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>deadline<span class="token punctuation">.</span><span class="token function">timeRemaining</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> currentTask <span class="token operator">=</span> taskQueue<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">currentTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">wookLoop</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">deadline</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// 这一帧还有剩余时间或者定义的时间到了, 就要执行任务了, 前提是有任务</span>
  <span class="token comment">// 这一帧没有剩余时间了, 直接放弃任务控制权, 执行权交给浏览器</span>
  <span class="token keyword">while</span> <span class="token punctuation">(</span>
    <span class="token punctuation">(</span>deadline<span class="token punctuation">.</span><span class="token function">timeRemaining</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">||</span> deadline<span class="token punctuation">.</span><span class="token function">didTimeout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
    taskQueue<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span>
  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">performUnitOfWork</span><span class="token punctuation">(</span>deadline<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 还有任务的话, 接着向浏览器申请下一个时间片</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>taskQueue<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">requestIdleCallback</span><span class="token punctuation">(</span>wookLoop<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeout</span><span class="token operator">:</span> <span class="token number">1000</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token function">requestIdleCallback</span><span class="token punctuation">(</span>wookLoop<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeout</span><span class="token operator">:</span> <span class="token number">1000</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="副作用是什么"><a href="#副作用是什么" class="header-anchor">#</a> 副作用是什么？</h2> <p><code>副作用</code>是函数式编程中的概念，是指<code>在函数执行过程中对外部环境的影响</code>。如果一个函数同时满足以下两个条件，则这个函数称为<code>纯函数</code>。</p> <ol><li>相同的输入始终获得相同的输出。</li> <li>不会修改程序的状态或者引起副作用</li></ol> <p><strong>纯函数</strong>
相同的输入一直能够得到相同的输出，没有修改程序的状态。因此<strong>是纯函数</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p><strong>不是纯函数</strong>
这里有一个随机数，导致相同的输入出现不同的输出结果。<strong>不是纯函数</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> x <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">+</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>修改了函数外部的变量， 因此<strong>也不是纯函数</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">&quot;chenjiang&quot;</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p><strong>注：除了修改函数外部变量之外，调用 DOM 的 API、I/O 操作、控制台打印信息等<code>函数调用过程中，外部可观察到变化</code>都属于副作用。</strong></p> <h2 id="时间切片-time-slice"><a href="#时间切片-time-slice" class="header-anchor">#</a> 时间切片（Time slice）</h2> <p>JS 是单线程，但我们在运行比较大的任务时候，很容易造成页面假死状态。</p> <p>原理：就是将一个大任务，切割成许多小任务，分散到每一帧中执行，留足时间给<code>layout</code>和<code>paint</code>阶段，这样就可以保证流畅度。</p> <p>做一个简单的案例：往页面中插入 10w 条 DOM 元素。</p> <h3 id="简单暴力做法"><a href="#简单暴力做法" class="header-anchor">#</a> 简单暴力做法</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token operator">&lt;</span>ul <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;list&quot;</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> listDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;.list&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">100000</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> li <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">&quot;li&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  li<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  listDom<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>li<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>发现页面一直加载中，出现假死的情况</p> <p><img src="https://img-blog.csdnimg.cn/2d097ab17d894b6193f8f04b19120e2f.png" alt="在这里插入图片描述"></p> <h3 id="使用-documentfragment-文档碎片稍作优化"><a href="#使用-documentfragment-文档碎片稍作优化" class="header-anchor">#</a> 使用 documentFragment 文档碎片稍作优化</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token operator">&lt;</span>ul <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;list&quot;</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> listDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;.list&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> documentFragment <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createDocumentFragment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">100000</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> li <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">&quot;li&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  li<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  documentFragment<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>li<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

listDom<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>documentFragment<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>比暴力解法稍微好点，但是还是有些卡顿。这一帧卡了 10s 多</p> <p><img src="https://img-blog.csdnimg.cn/133e7c3309074c9a8f786636225711dc.png" alt="在这里插入图片描述"></p> <h3 id="使用-requestanimationframe"><a href="#使用-requestanimationframe" class="header-anchor">#</a> 使用 requestAnimationFrame</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token operator">&lt;</span>ul <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;list&quot;</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">&gt;</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> listDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;.list&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 总共10w条</span>
<span class="token keyword">const</span> total <span class="token operator">=</span> <span class="token number">100000</span><span class="token punctuation">;</span>
<span class="token comment">// 每页20条数据，也就是每一帧需要渲染多少数据</span>
<span class="token keyword">const</span> once <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token comment">// 总共多少页</span>
<span class="token keyword">const</span> page <span class="token operator">=</span> total <span class="token operator">/</span> once<span class="token punctuation">;</span>
<span class="token comment">// 当前渲染到多少条了, 索引值</span>
<span class="token keyword">const</span> index <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">/**
 *
 * @param {*} currentTotal 还剩下多少条
 * @param {*} currentIndex 当前渲染第几页
 */</span>
<span class="token keyword">const</span> <span class="token function-variable function">render</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">currentTotal<span class="token punctuation">,</span> currentIndex</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>currentTotal <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>

  <span class="token comment">// 每页多少条</span>
  <span class="token keyword">const</span> pageSize <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>currentTotal<span class="token punctuation">,</span> once<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">requestAnimationFrame</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> fragment <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createDocumentFragment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> pageSize<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> li <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">&quot;li&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      li<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> currentIndex <span class="token operator">+</span> i<span class="token punctuation">;</span>
      fragment<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>li<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    listDom<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>fragment<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 下一帧渲染</span>
    <span class="token function">render</span><span class="token punctuation">(</span>currentTotal <span class="token operator">-</span> pageSize<span class="token punctuation">,</span> currentIndex <span class="token operator">+</span> pageSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token function">render</span><span class="token punctuation">(</span>total<span class="token punctuation">,</span> index<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><img src="https://img-blog.csdnimg.cn/12e2cdd46abf4ffc86e43fa9dbec62f9.png" alt="在这里插入图片描述">
任务都分给每一帧渲染了，一帧只花费 16.7ms，看起来不卡顿。</p> <p>参考文章：</p> <ul><li>https://juejin.cn/post/6844903938894872589</li></ul></div> <footer class="page-edit"><!----> <!----></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/tech-document/react/React架构演变.html" class="prev">
        React架构演变
      </a></span> <!----></p></div> </main></div><div class="global-ui"><!----><!----></div></div>
    <script src="/tech-document/assets/js/app.7336957d.js" defer></script><script src="/tech-document/assets/js/2.4e1184b4.js" defer></script><script src="/tech-document/assets/js/40.cc2c8a0d.js" defer></script><script src="/tech-document/assets/js/12.c2ba2865.js" defer></script>
  </body>
</html>
